`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    20:49:02 06/03/2012 
// Design Name: 
// Module Name:    alu_level3 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module ALU3(
		input systemclock,
		input reset,
		input fsmAluReq,
		input [2:0] fsmAluOpt,
		input [18:0] chrAluData,
		input [18:0] stackAluData,
		
		output reg aluStackPop =0,
		output reg [1:0] aluChrEn,
		output reg	 [18:0] aluChrData,
		output reg ALUflag=0 
    );

		parameter ADD = 3'b001;
		parameter SUB = 3'b010;
		parameter MUL = 3'b011;
		parameter DIV = 3'b101;
		
		
reg done=0;
reg [2:0] TempOp;
reg [2:0] Opt;
wire suc_plus,suc_minus,suc_mul,suc_div;		

wire [15:0] data1;
wire [15:0] data2;
wire [1:0] 	pPos1;
wire [1:0] 	pPos2;
wire 			isNeg1;
wire 			isNeg2;


wire [15:0] result_plus;
wire [1:0]	pPosRes_plus;
wire 			isNeg_plus;

wire [15:0] result_minus;
wire [1:0]	pPosRes_minus;
wire 			isNeg_minus;

wire [15:0] result_mul;
wire [1:0]	pPosRes_mul;
wire 			isNeg_mul;

wire [15:0] result_div;
wire [1:0]	pPosRes_div;
wire 			isNeg_div;


assign data1=chrAluData[15:0];
assign pPos1=chrAluData[17:16];
assign data2=stackAluData[15:0];
assign pPos2=stackAluData[17:16];
assign isNeg1=chrAluData[18];
assign isNeg2=stackAluData[18];

		
		
add3 adder(
			.data1(data1),
			.data2(data2),
			.position1(pPos1),
			.position2(pPos2),
			.isNeg1(isNeg1),
			.isNeg2(isNeg2),
			.enable(Opt),
			.done(done),
			.reset(reset),
			.sysclk(systemclock),
			.result(result_plus),
			.position(pPosRes_plus),
			.isNeg(isNeg_plus),
			.suc(suc_plus)
			);
minors3 suber(
			.data1(data1),
			.data2(data2),
			.position1(pPos1),
			.position2(pPos2),
			.isNeg1(isNeg1),
			.isNeg2(isNeg2),
			.enable(Opt),
			.done(done),
			.reset(reset),
			.sysclk(systemclock),
			.result(result_minus),
			.position(pPosRes_minus),
			.isNeg(isNeg_minus),
			.suc(suc_minus)
			);
			
multiply3 multr(
			.opnum1(data2),
			.opnum2(data1),
			.pPos1(pPos2),
			.pPos2(pPos1),
			.isNeg1(isNeg2),
			.isNeg2(isNeg1),
			.enable(Opt),
			.done(done),
			.reset(reset),
			.sysclk(systemclock),
			.result1(result_mul),
			.pPosRes(pPosRes_mul),
			.isNeg(isNeg_mul),
			.suc(suc_mul)
			);
			
divide3 diver(
			.data1(data1),
			.data2(data2),
			.pPos1(pPos1),
			.pPos2(pPos2),
			.isNeg1(isNeg1),
			.isNeg2(isNeg2),
			.enable(Opt),
			.done(done),
			.reset(reset),
			.sysclk(systemclock),
			.result(result_div),
			.pPosRes(pPosRes_div),
			.isNeg(isNeg_div),
			.suc(suc_div)
			);
		always @ (posedge systemclock) 
			if ( fsmAluReq ) begin
				
				aluStackPop = 1'b1;
				done = 0;
				aluChrEn 	= 2'b01;	
				
				TempOp	= fsmAluOpt;
				Opt = fsmAluOpt;

			end else if (|{suc_minus,suc_plus,suc_mul,suc_div})
					begin
					Opt = 3'b000;

					case(TempOp)
					ADD:begin
						ALUflag =1;
						aluChrData ={isNeg_plus,pPosRes_plus,result_plus};
						end
					SUB:begin
						aluChrData ={isNeg_minus,pPosRes_minus,result_minus};
						ALUflag = 0;
						end
					MUL:begin
						ALUflag = 1;
						aluChrData ={isNeg_mul,pPosRes_mul,result_mul};
						end
					DIV:begin
						ALUflag = 0;
						aluChrData ={isNeg_div,pPosRes_div,result_div};
						end
					default:
						aluChrData =aluChrData;
					endcase
					aluChrEn = 2'b10;
					aluStackPop = 1'b0;
					done =1;
			end else begin
				aluStackPop	=1'b0;
				aluChrEn = 2'b00;
				end
endmodule
